﻿#include "ZShellDesktopViewer.h"

static HWND g_workerw = 0;
static HWND g_defview = 0;
static BOOL CALLBACK EnumWndCallback(HWND tophandle, LPARAM /*topparamhandle*/) {
    HWND p = ::FindWindowEx(tophandle, 0, L"SHELLDLL_DefView", 0);
    if (p != 0) {
        g_defview = p;
        g_workerw = ::FindWindowEx(0, tophandle, L"WorkerW", 0);
    }
    return true;
}

static QWebEngineView *CreateWebview(QScreen *screen, int index, int offset) {

    QStringList args = qApp->arguments();

    auto webview = new QWebEngineView();
    webview->setWindowTitle("desktop_frame" + QString::number(index));
    webview->setWindowFlags(Qt::FramelessWindowHint | Qt::Tool);
    webview->setAttribute(Qt::WA_TranslucentBackground);
//    webview->setAttribute(Qt::WA_TransparentForMouseEvents);
//    webview->setAttribute(Qt::WA_InputMethodTransparent);
//    webview->setAttribute(Qt::WA_InputMethodEnabled, false);
//    webview->setInputMethodHints(Qt::ImhNone);
//    webview->setContextMenuPolicy(Qt::NoContextMenu);

    QRect rect = screen->geometry();
    webview->setGeometry(rect);

    webview->setObjectName("desktop_webview" + QString::number(index));
    webview->setWindowTitle("desktop_webview" + QString::number(index));

    //表示一样的
    QString localFile;
    if (args.contains("-url")) {
        int index = args.indexOf("-url");
        if (index != -1) {
            QStringList url1 = args.mid(index + 1, 1);
            if (!url1.isEmpty()) {
                localFile = url1.first();
            }
        }
    }
    QString key = QString("-url%1").arg(index);
    if (args.contains(key)) {
        int index = args.indexOf(key);
        if (index != -1) {
            QStringList url1 = args.mid(index + 1, 1);
            if (!url1.isEmpty()) {
                localFile = url1.first();
            }
        }
    }

    int volume = 0;
    if (args.contains("-volume")) {
        int index = args.indexOf("-volume");
        if (index != -1) {
            QStringList url1 = args.mid(index + 1, 1);
            if (!url1.isEmpty()) {
                volume = url1.first().toInt();
                if (volume < 0) {
                    volume = 0;
                }
                if (volume > 100) {
                    volume = 100;
                }
            }
        }
    }

    int delay = -1;
    if (args.contains("-delay")) {
        int index = args.indexOf("-delay");
        if (index != -1) {
            QStringList url1 = args.mid(index + 1, 1);
            if (!url1.isEmpty()) {
                delay = url1.first().toInt();
            }
        }
    }

    QString background = "#515C6B";
    if (args.contains("-background")) {
        int index = args.indexOf("-background");
        if (index != -1) {
            QStringList url1 = args.mid(index + 1, 1);
            if (!url1.isEmpty()) {
                background = url1.first();
            }
        }
    }

    webview->page()->profile()->settings()->setAttribute(QWebEngineSettings::AllowRunningInsecureContent, true);
    webview->page()->profile()->settings()->setAttribute(QWebEngineSettings::PlaybackRequiresUserGesture, false);
    webview->page()->profile()->settings()->setAttribute(QWebEngineSettings::WebGLEnabled, true);
    webview->page()->profile()->settings()->setAttribute(QWebEngineSettings::ShowScrollBars, false);
    webview->page()->profile()->settings()->setAttribute(QWebEngineSettings::LocalContentCanAccessFileUrls, true);
    QObject::connect(webview->page(), &QWebEnginePage::windowCloseRequested, webview, [&] {
        qApp->quit();
    }, Qt::QueuedConnection);

    if (args.contains("-bottom")) {
        ::SetParent((HWND)webview->winId(), g_workerw);
    } else if (args.contains("-top")) {
        ::SetParent((HWND)webview->winId(), g_defview);
    } else {
        ::SetParent((HWND)webview->winId(), g_workerw);
    }
    webview->setFixedSize(screen->geometry().size());
    webview->show();
    webview->activateWindow();

    webview->move(QPoint(rect.x(), rect.y() + 2 * offset));

    webview->page()->setBackgroundColor(Qt::transparent);
    if (localFile.indexOf("https://") == 0 || localFile.indexOf("http://") == 0) {
        webview->load(QUrl(localFile));
    } else {
        QFileInfo fileInfo(localFile);
        if (fileInfo.exists()) {
            static QMimeDatabase mdb;
            QMimeType mtype = mdb.mimeTypeForFile(fileInfo.absoluteFilePath());
            if (mtype.name().contains("image")) {
                QString content ="<!DOCTYPE html><html lang=\"zh-CN\">"
                                 "<head><style type=\"text/css\">"
                                 "*{margin:0px;padding:0px;}"
                                 "img{%1;display:block;position:absolute;top:50%;left:50%;transform:translate3d(-50%,-50%,0);}"
                                 "</style></head>"
                                 "<body style=\"background-color:" + background + "; width:%2px;height:%3px;\" onload=\"var n = %4; if (n > 0) { window.setTimeout(function() { window.close(); }, n); }"
                                 " var node = document.querySelector('img'); if(node) {node.src='%5'}\">"
                                 "<img src=\"\" /></body></html>";

                QString whinfo = "height:100%";
                QImage image(localFile);
                float flperImage = (float)image.width() / (float)image.height();
                float flperScreen = (float)webview->width() / (float)webview->height();
                if (flperImage > flperScreen) {
                    whinfo = "width:100%";
                }
                content = content.arg(whinfo,
                                      QString::number(webview->width()),
                                      QString::number(webview->height()),
                                      QString::number(delay),
                                      QUrl::fromLocalFile(localFile).toString());
                webview->setHtml(content);
            } else if (mtype.name().contains("video")) {
                QString content =
                    "<!DOCTYPE html><html lang=\"zh-CN\">"
                    "<head><style type=\"text/css\">"
                    "*{margin:0px;padding:0px;}"
                    "</style></head>"
                    "<body style=\"background-color:" + background + "; width:%1px;height:%2px;\"  onload=\" var node = document.querySelector('video'); var n = %3; if (n > 0) { window.setTimeout(function() { window.close(); }, n); } else if (n == 0) { node.loop='loop'; } "
                    " var volume = %4; if (volume == 0) { node.volume=0; } else { node.volume=%5/100.0; }\"  >"
                    "<video style=\"width:100%;height:100%;\" autoplay=\"autoplay\" onended=\"var m = %6; if (m == -1) { window.close(); } \" >"
                    "<source src=\"%7\"></video></body></html>";
                content = content.arg(QString::number(webview->width()),
                                      QString::number(webview->height()),
                                      QString::number(delay),
                                      QString::number(volume),
                                      QString::number(volume),
                                      QString::number(delay),
                                      QUrl::fromLocalFile(localFile).toString());
                webview->setHtml(content);
            }
        }
    }

    return webview;
}



ZShellDesktopViewer::ZShellDesktopViewer() {

    HWND hwndProgram = ::FindWindow(L"Progman", L"Program Manager");
    ::SendMessageTimeout(hwndProgram, 0x052C, 0, 0, SMTO_NORMAL, 1000, 0);
    ::EnumWindows(EnumWndCallback, 0);

    if (g_workerw) {
        this->createViews();
    }

    QAction *action = menu_->addAction(QString::fromWCharArray(L"退出"));
    connect(action, &QAction::triggered,
    this, [&] {
        qApp->exit();
    });

    if (qApp->arguments().contains("-tray")) {
        tray_.setIcon(QIcon(":/ZShellDesktopViewer/logo.ico"));
        tray_.setContextMenu(menu_);
        tray_.show();
    }


    timerCheckDesktop_ = this->startTimer(1000);
}

ZShellDesktopViewer::~ZShellDesktopViewer() {
    for (auto itr = infos_.begin(); itr != infos_.end(); ++itr) {
        DesktopInfo &info = *itr;
        delete info.webview;
    }
}

void ZShellDesktopViewer::createViews() {
    QList<QScreen*> screens = qApp->screens();
    for (int i = screens.count() - 1; i >= 0; --i) {
        QScreen *screen = screens.at(i);

        DesktopInfo info;
        info.screen = screen;
        info.webview = CreateWebview(screen, i, this->screensOffset());
        infos_.append(info);
    }

}

void ZShellDesktopViewer::updateViews() {
    int offset = screensOffset();
    int index = 0;
    for (auto itr = infos_.begin(); itr != infos_.end(); ++itr, ++index) {
        DesktopInfo &info = *itr;

        QRect rect = info.screen->geometry();
        QPoint pos = rect.topLeft();
        if (pos.y() == 0) {
            pos.setY(pos.y() + offset);
        } else {
            pos.setY(pos.y() + 2 * offset);
        }


        if (info.webview != nullptr && info.webview->size() != rect.size()) {
            info.webview->show();
            info.webview->raise();
            info.webview->setFixedSize(rect.size());
            info.webview->move(pos);
            info.webview->activateWindow();
        }

        if (info.pos != pos && info.webview != nullptr) {
            info.pos = pos;
        }
    }

}

int ZShellDesktopViewer::screensOffset() {
    //多块屏幕的时候, 需要处理偏移问题
    QList<QScreen*> screens = qApp->screens();
    QMultiMap<int, QScreen*> screensSorted;
    foreach (QScreen *screen, screens) {
        screensSorted.insert(screen->geometry().y(), screen);
    }
    if (screensSorted.isEmpty())
        return 0;

    int offset = 0 - screensSorted.begin().key();
    return offset;
}

void ZShellDesktopViewer::timerEvent(QTimerEvent *e) {
    if (e->timerId() == timerCheckDesktop_) {
        HWND workerwStore = g_workerw;
        HWND hwndProgram = ::FindWindow(L"Progman", L"Program Manager");
        ::SendMessageTimeout(hwndProgram, 0x052C, 0, 0, SMTO_NORMAL, 1000, 0);
        ::EnumWindows(EnumWndCallback, 0);
        if (g_workerw != workerwStore) {
            //需要重新生成界面
            for (auto itr = infos_.begin(); itr != infos_.end(); ++itr) {
                DesktopInfo &info = *itr;
                delete info.webview;
            }
            infos_.clear();
            this->createViews();
        } else {
            this->updateViews();
        }
    }
    QObject::timerEvent(e);
}
